// console.log(process);
const fp = require('lodash/fp');
const fs = require('fs');
// 尝试使用 IO 函子，要注意的是，返回的是一个函数，将函数中一些不纯的结果返回给调用者
class IO {
  static of(x) {
    // console.log(1);
    return new IO(function() { return x });
  }

  constructor(fn) {
    this._value = fn;
  }

  map(fn) {
    // 这个地方有个误区，刚开始使用的是 IO.of，后来发生了一个比较有趣的现象，最终我调用的时候，是 r._value()() 才能调用
    // 为什么呢？在这里调用了 IO.of 可以看一下 of 方法，它将传入的参数 放置到了一个函数里面，所以这个地方 函数 嵌套了两层，所以要 ()()

    // return IO.of(fp.flowRight(fn, this._value));

    // 为什么要调用 new IO 呢？
    // 仔细看看，new IO调用的时候，传入了 "一个" 函数，flowRight 就是让他最终返回一个函数，下面的 p => p.execPath 就是给这个函数赋值
    return new IO(fp.flowRight(fn, this._value));
  }

  join() {
    return this._value();
  }

  flatMap(fn) {
    return this.map(fn).join();
  }
}

const r = IO.of(process).map(p => p.execPath);
// console.log(r._value());

// 什么是 monad 函子，同时具有 of 和 join 的函子就可以称为 monad 函子
// 写一个读取文件的方法
const readFile = function(fileName) {
  return new IO(function() {
    return fs.readFileSync(fileName, 'utf-8');
  });
}

const log = function(x) {
  return new IO(function() {
    console.log(x);
    return x;
  });
}

const r1 = readFile('package.json')
             .map(fp.toUpper)
             .flatMap(log)
             .join();
// console.log(r1);
// console.log(r1('package.json')._value()._value());
console.log(readFile('package.json'))
